package de.zainodis.authorlist.model.parsing;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Xml;

import de.zainodis.commons.utils.XmlUtils;

public abstract class XmlFeedParser<T> {

   /** List root containing all parseable elements */
   protected static final String LIST_ROOT = "plist";
   /** The version of a {@link AuthorsCreationParser#LIST_ROOTs} */
   protected static final String VERSION_ATTRIBUTE = "version";
   /** A key element is always succeeded by a value element */
   protected static final String KEY_ELEMENT = "key";
   /** A string value */
   protected static final String STRING_ELEMENT = "string";
   /** A float value */
   protected static final String DECIMAL_ELEMENT = "real";
   /** A collection of some kind */
   protected static final String ARRAY_ELEMENT = "array";

   /** List of items being parsed and afterwards returned */
   private Collection<T> items = new ArrayList<T>();

   /**
    * This doesn't really serve a purpose with the current setup, but could be
    * used to compare versions and only proceed with parsing, if the versions
    * differ. If the version matches the cached content, that content could be
    * used instead of parsing it all over again.
    */
   private String listVersion;

   public void parse(InputStream stream) throws XmlPullParserException, IOException {
	 try {
	    XmlPullParser parser = Xml.newPullParser();
	    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
	    parser.setInput(stream, null);
	    parser.nextTag();
	    processParsedElements(parse(parser));
	 } finally {
	    stream.close();
	 }
   }

   /**
    * This method should be used to directly process parsed items, such as
    * caching them etc.
    * 
    * @param items
    *           the items that have been parsed.
    */
   public abstract void processParsedElements(Collection<T> items);

   public Collection<T> parse(XmlPullParser parser) throws XmlPullParserException, IOException {

	 while (parser.next() != XmlPullParser.END_DOCUMENT) {
	    int eventType = parser.getEventType();

	    if (eventType == XmlPullParser.START_TAG) {
		  String elementName = parser.getName();

		  if (LIST_ROOT.equals(elementName)) {
			Map<String, String> attributes = XmlUtils.parseAttributes(parser);
			// Obtain the version list
			listVersion = attributes.get(VERSION_ATTRIBUTE);
		  } else {
			handleStartTag(elementName, parser);
		  }

	    } else if (eventType == XmlPullParser.END_TAG) {
		  handleEndTag(parser.getName(), parser);
	    }
	 }
	 return items;
   }

   public abstract void handleStartTag(String name, XmlPullParser parser)
	    throws XmlPullParserException, IOException;

   public abstract void handleEndTag(String name, XmlPullParser parser)
	    throws XmlPullParserException, IOException;

   protected void addItem(T newItem) {
	 items.add(newItem);
   }

   public String getListVersion() {
	 return listVersion;
   }
}
